package com.cloudkinto.common.common;

import cn.hutool.core.util.StrUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.regex.Pattern;

/**
 * @Auther: fanting
 * @Date: 2018/11/8 10:50
 * @Description:
 */
public class DateUtils {

    private static final String DATE_REGEX1 = "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$";
    private static final String DATE_REGEX2 = "^\\d{4}/(0[1-9]|1[0-2])/(0[1-9]|[12]\\d|3[01])$";

    private static final String DATE_TIME_REGEX1 =
            "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]) ([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)$";
    private static final String DATE_TIME_REGEX2 =
            "^\\d{4}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])([01]\\d|2[0-3])([0-5]\\d){2}$";

    /**
     * 判断日期格式是否正确 yyyy-MM-dd
     */
    public static boolean regexCheckDate1(String date) {
        if (StrUtil.isBlank(date)) {
            return false;
        }
        return Pattern.matches(DATE_REGEX1, date);
    }

    /**
     * 判断日期格式是否正确 yyyy/MM/dd
     */
    public static boolean regexCheckDate2(String date) {
        if (StrUtil.isBlank(date)) {
            return false;
        }
        return Pattern.matches(DATE_REGEX2, date);
    }

    /**
     * 验证日期格式是否正确 yyyy-MM-dd HH:mm:ss
     *
     * @param input 日期字符串
     * @return true/false
     */
    public static boolean regexCheckDateTime1(String input) {
        return Pattern.matches(DATE_TIME_REGEX1, input);
    }

    /**
     * 验证日期格式是否正确 yyyyMMddHHmmss
     *
     * @param input 日期字符串
     * @return true/false
     */
    public static boolean regexCheckDateTime2(String input) {
        return Pattern.matches(DATE_TIME_REGEX2, input);
    }

    public static int getDiffDay(String beginTime, String endTime) {
        Date now = new Date();
        Date begin = beginTime != null && !"".equals(beginTime) ? DateUtils.stringFormatToDate(beginTime) : DateUtils.passingDate(now, -6);
        Date end = endTime != null && !"".equals(endTime) ? DateUtils.stringFormatToDate(endTime) : now;
        int diffDay = DateUtils.daysBetween(begin, end);
        return diffDay;
    }


    public static LocalDate convert(Date date) {
        return convert(date, null);
    }

    /**
     * 将java.util.Date转换为java.time.LocalDate
     * @param date 要转换的Date对象（可以为null）
     * @param zoneId 时区（如不指定可使用系统默认时区）
     * @return 转换后的LocalDate对象，若输入为null则返回null
     */
    public static LocalDate convert(Date date, ZoneId zoneId) {
        if (date == null) {
            return null;
        }

        // 如果未指定时区，使用系统默认时区
        ZoneId usedZoneId = (zoneId != null) ? zoneId : ZoneId.systemDefault();

        // 转换步骤：Date -> Instant -> ZonedDateTime -> LocalDate
        return date.toInstant()
                .atZone(usedZoneId)
                .toLocalDate();
    }

    /**
     * 获取两个日期相差多少天
     *
     * @param smdate
     * @param bdate
     * @return
     * @throws ParseException
     */
    public static int daysBetween(Date smdate, Date bdate) {
        Calendar cal = Calendar.getInstance();

        cal.setTime(smdate);

        long time1 = cal.getTimeInMillis();

        cal.setTime(bdate);

        long time2 = cal.getTimeInMillis();

        long between_days = (time2 - time1) / (1000 * 3600 * 24);

        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 比较两个时间的时间差，比较出时间差值，单位天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    public static int differentWeeksByMillisecond(Date date1, Date date2) {
        int weeks = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24 * 840));
        return weeks;
    }

    public static int differentMonthsByMillisecond(Date date1, Date date2) {
        int months = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24 * 3600));
        return months;
    }


    public static int differentMinByMillisecond(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 60));
        return days;
    }

    public static int getMonthsNum(Date date1, Date date2) {
        Temporal temporal1 = LocalDate.parse(dateFormatToString(date1));
        Temporal temporal2 = LocalDate.parse(dateFormatToString(date2));
        // 方法返回为相差月份
        long months = ChronoUnit.MONTHS.between(temporal1, temporal2);
        return Integer.valueOf((int) months);
    }

    public static String getGeneratorYYMMDDStr() {
        String result = "";
        String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
        String year = strNow[0];
        String month = strNow[1];
        String day = strNow[2];
        String yearStr = year.toString().substring(2);
        result = result + yearStr + month + day;
        return result;
    }


    public static String getGeneratorYYMMStr() {
        String result = "";
        String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
        String year = strNow[0];
        String month = strNow[1];
        String yearStr = year.toString().substring(2);
        result = result + yearStr + month;
        return result;
    }

    // 获得某天最大时间 2020-02-19 23:59:59
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        ;
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    // 获得某天最小时间 2020-02-17 00:00:00
    public static Date getStartOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }


    public static String addOneDay(String dateStr, int daysToAdd) {
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 将字符串解析为 LocalDate
        LocalDate date = LocalDate.parse(dateStr, formatter);

        // 往后推一天
        LocalDate nextDay = date.plusDays(daysToAdd);

        // 将结果格式化为字符串
        return nextDay.format(formatter);
    }
    //日期推移 向前或向后推移？天
    public static Date passingDate(Date date, int days) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, days);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    public static Date passingDate(String dateStr, int days) {
        Date date = DateUtils.stringFormatToDate(dateStr);
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, days);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    public static Date passingDateHour(Date date, int hours) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, hours);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    public static Date passingDateMin(Date date, int min) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, min);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    public static Date passingDateSec(Date date, int sec) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, sec);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    /**
     * 功能描述 日期推移 单位：月
     *
     * @author zhujiale
     * @date 2022/3/10
     */
    public static Date passingDateMonth(Date date, int months) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.MONTH, months);//把日期往后增加一月.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一月的结果
        return date;
    }

    /**
     * 功能描述 日期推移 单位：年
     *
     * @author zhujiale
     * @date 2022/3/10
     */
    public static Date passingDateYear(Date date, int years) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, years);//把日期往后增加一年.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一年的结果
        return date;
    }

    public static String getTodayYYMMStr() {
        return getTodayYYMMStr(new Date());
    }

    public static String getTodayYYMMStr(Date date) {
        return dateFormatToString(date, "yyyyMM");
    }


    public static String dateFormatToString(Date date, String pattern) {
        if (pattern == null || "".equals(pattern)) {
            pattern = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String dateStr = sdf.format(date);
        return dateStr;
    }

    public static Date stringFormatToDate(String dateStr) {
        return stringFormatToDate(dateStr, null);
    }


    public static String dateFormatToString(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(date);
        return dateStr;
    }

    public static Date stringFormatToDate(String dateStr, String pattern) {
        if (pattern == null || "".equals(pattern)) {
            pattern = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date = null;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    public static Date stringFormatToDateHms(String dateStr) {
        return stringFormatToDateHms(dateStr, null);
    }

    public static Date stringFormatToDateHms(String dateStr, String pattern) {
        if (pattern == null || "".equals(pattern)) {
            pattern = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.ENGLISH);
        Date date = null;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }


    /**
     * 获取时间所在月第一天和最后一天
     *
     * @param start_time
     * @param num        0-第一天  1-最后一天
     * @param month      >0 下个月   <0 上个月 =0 当前月
     * @return
     */
    public static Date getEndDayOrOneDay(Date start_time, int num, int month) {
        Calendar cale = Calendar.getInstance();
        if (num == 0) {
            // 获取前月的第一天
            cale = Calendar.getInstance();
            cale.setTime(start_time);
            cale.add(Calendar.MONTH, month + 0);
            cale.set(Calendar.DAY_OF_MONTH, 1);
        } else {
            // 获取前月的最后一天
            cale = Calendar.getInstance();
            cale.setTime(start_time);
            cale.add(Calendar.MONTH, month + 1);
            cale.set(Calendar.DAY_OF_MONTH, 0);
        }
        return cale.getTime();
    }
}
